package org.example.wax.manager;

import com.example.sixteen.jt.lib.JTAnt;
import com.example.sixteen.jt.lib.Reader;
import org.example.wax.constant.StatusConstant;
import org.example.wax.domain.MarkItem;
import org.example.wax.domain.NetworkStatus;
import org.example.wax.exception.ServiceException;
import org.example.wax.manager.listener.OnCabinetManagerListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class SixteenReader extends Reader implements Reader.OnReaderListener {

    private static final Logger logger = LoggerFactory.getLogger(SixteenReader.class);

    private NetworkStatus status = new NetworkStatus();

    private Integer index;

    private String host;

    /**
     * 使能天线号
     */
    private List<Integer> antIndexes;

    /**
     * 实际箱门号
     */
    private List<Integer> boxIndexes;

    private Map<Integer, Integer> antBoxMap = new ConcurrentHashMap<>();

    private Map<Integer, List<Integer>> boxAntMap = new ConcurrentHashMap<>();

    private OnCabinetManagerListener listener;

    private String eventId;

    /**
     * 缓存已开箱门
     */
    private List<Integer> openedBoxes = new ArrayList<>();

    /**
     * 缓存需要盘点的箱门号
     */
    private List<Integer> needInvBoxes = new ArrayList<>();

    private List<String> indexes = new LinkedList<>();
    private List<MarkItem> markItems = new LinkedList<>();

    public SixteenReader(String ip, int index, List<Integer> antIndexes, List<Integer> boxIndexes) {
        this.index = index;
        this.host = ip;
        this.status.setIndex(index);
        this.status.setIp(ip);
        this.antIndexes = antIndexes;
        this.boxIndexes = boxIndexes;
        this.status.setBoxes(boxIndexes);
        this.status.setStatus(StatusConstant.STATUS_DISCONNECTED);
        setOnReaderListener(this);
    }

    public void checkLayout() {
        if (CollectionUtils.isEmpty(antIndexes) || CollectionUtils.isEmpty(boxIndexes)) {
            throw new ServiceException("RFID接收器天线号或天线号对应的箱门号未设置");
        }
        if (antIndexes.size() != boxIndexes.size()) {
            throw new ServiceException("RFID接收器的天线号的长度和天线号对应的箱门号的长度不一致");
        }
        for (int i = 0; i < antIndexes.size(); i++) {
            antBoxMap.put(antIndexes.get(i), boxIndexes.get(i));
            if (boxAntMap.containsKey(boxIndexes.get(i))) {
                boxAntMap.get(boxIndexes.get(i)).add(antIndexes.get(i));
            } else {
                List<Integer> list = new ArrayList<>();
                list.add(antIndexes.get(i));
                boxAntMap.put(boxIndexes.get(i), list);
            }
        }
        logger.info("antBox: {}", antBoxMap);
        logger.info("boxAnt: {}", boxAntMap);
    }

    public String getHost() {
        return host;
    }

    public Integer getIndex() {
        return index;
    }

    public void setOnCabinetManagerListener(OnCabinetManagerListener listener) {
        this.listener = listener;
    }

    public int getChannels(List<Integer> boxes) {
        int channels = 0;
        for (Integer box : boxes) {
            if (boxAntMap.containsKey(box)) {
                for (Integer ant : boxAntMap.get(box)) {
                    channels += (1 << (ant - 1));
                }
            }
        }
        return channels;
    }

    public int getAnt(Integer box) {
        if (boxAntMap.containsKey(box)) {
            int channels = 0;
            for (Integer ant : boxAntMap.get(box)) {
                channels += (1 << (ant - 1));
            }
            return channels;
        }
        return -1;
    }

    public NetworkStatus getStatus() {
        return this.status;
    }

    public void cacheOpened(List<Integer> boxes) {
        for (Integer box : boxes) {
            if (boxAntMap.containsKey(box)) {
                if (openedBoxes.indexOf(box) == -1) {
                    openedBoxes.add(box);
                }
                if (needInvBoxes.indexOf(box) == -1) {
                    needInvBoxes.add(box);
                }
            }
        }
    }

    public int cacheClosed(Integer box) {
        if (boxAntMap.containsKey(box)) {
            openedBoxes.remove((Object) box);

            int channels = 0;
            for (Integer ant : boxAntMap.get(box)) {
                channels += (1 << (ant - 1));
            }
            return channels;
        }
        return -1;
    }

    public boolean isAllClosed() {
        return openedBoxes.size() == 0;
    }

    public List<Integer> getNeedInvBoxes() {
        return needInvBoxes;
    }

    public int connectEx() {
        int ret = connect(this.host, 20058);
        if (ret == SUCCESS) {
            this.status.setStatus(StatusConstant.STATUS_CONNECTED);
        }
        return ret;
    }

    public int disconnectEx() {
        int ret = disconnect();
        if (ret == SUCCESS) {
            this.status.setStatus(StatusConstant.STATUS_DISCONNECTED);
        }
        return ret;
    }

    public int inventory(String eventId, int channels, int power, int invMs, int sleepMs, int times) {
        int ret;
        this.needInvBoxes.clear();
        this.indexes.clear();
        this.markItems.clear();
        this.eventId = eventId;

        JTAnt[] ants = new JTAnt[16];
        for (int i = 0; i < 16; i++) {
            JTAnt ant = new JTAnt();
            ant.setPower(power);
            ant.setWork(invMs);
            ant.setSleep(sleepMs);
            ant.setEnabled((channels >> i) & 1);
            ants[i] = ant;
        }
        if (setAnt(ants) != SUCCESS) {
            logger.error("Reader: {}, SET_ANT_FAILED", host);
            throw new ServiceException("设置天线失败");
        }
        ret = inventory(times);
        if (ret == SUCCESS) {
            this.status.setStatus(StatusConstant.STATUS_INVENTORYING);
        } else {
            logger.error("Reader: {}, INVENTORY_FAILED", host);
            throw new ServiceException("盘点失败");
        }
        return ret;
    }

    @Override
    public void onAlive(String ip) {

    }

    @Override
    public void onInventory(String ip, String epc, int ant, int rssi, int high) {
        logger.debug("onInventory: {}, {}, {}", ip, epc, ant);
        if (!antBoxMap.containsKey(Integer.valueOf(ant))) {
            return;
        }
        int box = antBoxMap.get(Integer.valueOf(ant));
        int idx = indexes.indexOf(epc);
        if (idx == -1) {
            MarkItem item = new MarkItem();
            item.setBox(box);
            item.setMark(epc);
            item.setAnt(ant);
            item.setRssi(rssi);
            item.setHigh(high);
            markItems.add(item);
            indexes.add(epc);
        } else {
            MarkItem item = markItems.get(idx);
            if (item.getHigh() == high) {
                if (markItems.get(idx).getRssi() < rssi) {
                    markItems.get(idx).setBox(box);
                    markItems.get(idx).setAnt(ant);
                    markItems.get(idx).setRssi(rssi);
                }
            }
        }
    }

    @Override
    public void onStop(String ip) {
        this.status.setStatus(StatusConstant.STATUS_CONNECTED);
        if (listener != null) {
            listener.onInventory(index, eventId, markItems);
        }
    }
}
